package uk.ac.lkl.lpp.model.xml;



import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import uk.ac.lkl.common.allocator.AllocatorModel;

import uk.ac.lkl.common.util.ds.AbstractNotifyingList;
import uk.ac.lkl.common.util.ds.ListHandle;

import uk.ac.lkl.lpp.model.PedagogyPlanModel;
import uk.ac.lkl.lpp.ui.BackCompat;


public class AllocationSetProcessor extends ModelElementProcessor {

    private static Logger logger = Logger.getLogger("ac.uk.lkl.lpp");


    public AllocationSetProcessor() {
        super("AllocationSet");
    }


    public void convertDataToElements(PedagogyPlanModel plan,
                                      Document document,
                                      Element pedagogyPlanElement) {
        Collection<ListHandle> listHandles = plan.getAllocatorModelClasses();

        for (ListHandle listHandle : listHandles) {
            Element allocationSetElement = document
                    .createElement("AllocationSet");
            pedagogyPlanElement.appendChild(allocationSetElement);

            AllocatorModel allocator = plan.getAllocatorModel(listHandle);

            String listName = listHandle.getName();
            if (listName != null)
                allocationSetElement.setAttribute("listName", listName);
            allocationSetElement.setAttribute("class", listHandle
                    .getListClassName());
            allocationSetElement.setAttribute("slots", Integer
                    .toString(allocator.getNumColumns()));

            AbstractNotifyingList list = allocator.getList();

            for (int i = 0; i < list.size(); i++) {
                Object object = list.get(i);
                List<Integer> allocations = allocator.getAllocations(object);

                for (int slot = 0; slot < allocations.size(); slot++) {
                    Integer allocation = allocations.get(slot);

                    if (allocation == 0)
                        continue;

                    Element allocationElement = document
                            .createElement("Allocation");
                    allocationElement
                            .setAttribute("index", Integer.toString(i));
                    allocationElement.setAttribute("slot", Integer
                            .toString(slot));
                    allocationElement.setAttribute("allocation", allocation
                            .toString());

                    allocationSetElement.appendChild(allocationElement);
                }

            }
        }
    }


    public void convertElementToData(PedagogyPlanModel plan, Element element) {

        try {
            String className = element.getAttribute("class");
            String listName = element.getAttribute("listName");

            // hack to convert pre 0.72 data files
            logger.info("*******className: " + className);

            if (BackCompat.isOldForm(className))
                className = BackCompat.upgrade(className);
            if (className.equals("uk.ac.lkl.lpp.model.ldo.TeachingMethod")) {
                logger.info("Alllocating table for TeachingMethod");
            }

            Class cl = Class.forName(className);

            String numSlotsString = element.getAttribute("slots");
            //int numSlots = Integer.parseInt(numSlotsString);
            int numSlots = plan.getNSubs();

            AbstractNotifyingList list = plan.getList(listName, cl);

            AllocatorModel model = new AllocatorModel(numSlots, list);

            BackCompat.backPatch(plan.getVersion(), model);

            NodeList allocations = element.getElementsByTagName("Allocation");
            int numAllocations = allocations.getLength();
            for (int i = 0; i < numAllocations; i++) {
                Node allocation = allocations.item(i);
                processAllocation(model, (Element) allocation);
            }

            plan.addAllocatorModel(listName, cl, model);
        }
        catch (NumberFormatException e) {
            // add warning
            e.printStackTrace();
        }
        catch (ClassNotFoundException e) {
            // hack! Do more here!
            e.printStackTrace();
        }
    }


    private void processAllocation(AllocatorModel model,
                                   Element allocationElement) {
        try {
            String indexString = allocationElement.getAttribute("index");
            int index = Integer.parseInt(indexString);
            if (index < 0) {
                // todo: add warning and ignore this allocation
            }

            String slotString = allocationElement.getAttribute("slot");
            int slot = Integer.parseInt(slotString);
            if (slot < 0 || slot >= model.getNumColumns()) {
                // todo: warning and ignore this allocation
            }

            String allocationString = allocationElement
                    .getAttribute("allocation");
            int allocation = Integer.parseInt(allocationString);
            if (allocation < 0) {
                // warning and ignore
            }

            // todo: allow use of indices on allocator model rather
            // than explicit object
            Object object = model.getList().get(index);

            model.setAllocation(object, slot, allocation);
        }
        catch (NumberFormatException e) {
            e.printStackTrace();
            // todo: add to list of warnings
        }
    }
}
